#pragma once

#include"epoll.h"
#include <sys/eventfd.h>

class EventLoop{
    private:
        using callback_func=std::function<void(void)>;
        using task=std::function<void(void)>;
        std::thread::id _thread_id;//线程id
        int _timeout;//epoll的超时时间
        int _eventfd;//用于通知子线程有任务需要处理
        std::mutex _mutex;//用于任务池的互斥锁,因为任务池是由主线程和子线程共同操作的
        Channel _cannel;//用于eventfd事件，结合_tasks使用
        Epoll* _epoll;//用于监听连接事件
        TimerWheel _timer_wheel;//定时器轮,处理超时的连接
        std::vector<task> _tasks;//任务池,这个主要是给添加连接用的
        void ReadEventfd(){
            eventfd_t val=1;
            int n=eventfd_read(_eventfd,&val);
            if(n<0){
                perror("eventfd_read error");
                std::cout<<__LINE__<<std::endl;
                exit(1);
            }
        }
        void WeakUpEventfd(){
            int n=eventfd_write(_eventfd,1);
            if(n<0){
                perror("eventfd_write error");
                std::cout<<__LINE__<<std::endl;
                exit(1);
            }
        }
        void RunAllTasks(){
            std::lock_guard<std::mutex> lock(_mutex);
            for(auto& task:_tasks){
                task();
            }
            _tasks.clear();

        }
    public:
        EventLoop(std::thread::id thread_id):_thread_id(thread_id),_timeout(100),
        _timer_wheel(20,this),_epoll(new Epoll())
        {
            std::lock_guard<std::mutex> lock(_mutex);
            _epoll->SetTimeout(_timeout);//这个timeout是epoll的超时时间，不是timer_wheel的超时时间
            _eventfd=eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
            //_timer_wheel.SetTimeout(_timeout);
            if(_eventfd<0){
                perror("eventfd error");
                std::cout<<__LINE__<<std::endl;
                exit(1);
            }
            _cannel.SetFd(_eventfd);
            LOG(ly::LogLevel::DEBUG)<<"eventfd:"<<_eventfd;
            _cannel.SetEventLoop(this);
            _cannel.SetReadCallback(std::bind(&EventLoop::ReadEventfd,this));
            _cannel.EnableReadEvent();//fd是在channel的updata中添加进入epoll的
        }
        //设置epoll的超时时间
        void SetTimeout(int timeout){
            _timeout=timeout;
            _epoll->SetTimeout(_timeout);
        }
        //添加任务，这个是给主线程和connection用的
        void PushTask(const callback_func& callback){
            if(std::this_thread::get_id()==_thread_id){
                callback();
            }
            else{
                _tasks.push_back(callback);
                WeakUpEventfd();
            }
        }
        void Start(){
            while(true){
                std::vector<Channel*> channels;
                //获取待处理事件列表
                _epoll->Start(channels);
                //处理事件
                for(auto channel:channels){
                    //std::cout<<channel->Fd()<<std::endl;
                    channel->HandleEvent();
                    //TimerRefresh(channel->Fd());
                }
                //处理任务
                RunAllTasks();
            }
        }
        //更新一个连接的监听事件
        void UpdataEvent(Channel* channel){
            _epoll->Modify(channel);
        }
        //移除一个连接
        void RemoveEvent(Channel* channel){
            _epoll->Remove(channel);
        }
        //为一个连接添加定时任务
        bool AddTimerTask(int id,int timeout,const callback_func& callback){
            return _timer_wheel.TimerAdd(id,timeout,callback);
        }
        //刷新时间，因为有消息到来
        bool TimerRefresh(int id){
            return _timer_wheel.TimerRefresh(id);
        }
        //移除取消定时任务
        void TimerCancel(int id){
            _timer_wheel.TimerCancel(id);
        }
        //检查该id是否有定时任务
        bool HasTimerTask(int id){
            return _timer_wheel.HasTimerTask(id);
        }
        EventLoop* GetEpoll(){
            return this;
        }


};
//不允许使用不完整类
void Channel::Update(){ _loop->UpdataEvent(this); }
void Channel::Remove(){ _loop->RemoveEvent(this); }